﻿#include "decoder.h"
#include "libavcodec/codec.h"
#include <QDebug>

Decoder::Decoder()
{
}

Decoder::~Decoder()
{
    if(codec_ctx)
    {
        qDebug() << " avcodec_free_context(&codec_ctx);";
        avcodec_free_context(&codec_ctx);
    }
}

bool Decoder::openDecoder(AVCodecParameters* stream_params)
{
    if (stream_params == NULL)
    {
        return false;
    }
    //根据解码器id找到解码器
    const AVCodec* codec = avcodec_find_decoder(stream_params->codec_id);
    if (!codec)
    {
        avcodec_parameters_free(&stream_params);
        qDebug() << "can't find the codec id " << stream_params->codec_id;
        return false;
    }
    qDebug() << "find the AVCodec " << stream_params->codec_id;

    // mux.lock();
    //创建解码器上下文，并分配空间
    codec_ctx = avcodec_alloc_context3(codec);
    if(codec_ctx == NULL)
    {
        qDebug() << "codec_ctx = avcodec_alloc_context3(vcodec); error";
        return false;
    }
    ///复制参数到配置解码器上下文参数
    int ret = avcodec_parameters_to_context(codec_ctx, stream_params);
    if(ret < 0)
    {
        qDebug() << "avcodec_parameters_to_context(codec_ctx, stream_params); error";
        return false;
    }
    //释放深拷贝过来的 AVCodecParameters*
    avcodec_parameters_free(&stream_params);

    //八线程解码
    codec_ctx->thread_count = 8;
    codec_ctx->delay = 0;
    //低延迟
    codec_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;

    //打开解码器上下文
    //调用了 avcodec_alloc_context3 以经设置过codec 此处无需再设置
    int re = avcodec_open2(codec_ctx, NULL, NULL);
    if (re != 0)
    {
        avcodec_free_context(&codec_ctx);
        // mux.unlock();
        char buf[1024] = { 0 };
        av_strerror(re, buf, sizeof(buf) - 1);
        qDebug() << "avcodec_open2(codec_ctx, NULL, NULL);  error! :" << buf;
        return false;
    }
    // mux.unlock();
    qDebug() << "avcodec_open2(codec_ctx, NULL, NULL); success!";
    return true;
}

bool Decoder::sendAVPacketToDecoder(AVPacket *pkt)
{
    //容错处理
    if (pkt == NULL || pkt->size <= 0 || pkt->data == NULL)return false;
    // mux.lock();

    if (codec_ctx == NULL)
    {
        qDebug() << "codec_ctx == NULL -----" << "pkt->stream_index = " << pkt->stream_index;
        // mux.unlock();
        return false;
    }
    //发送给解码器进行解码
    int ret = avcodec_send_packet(codec_ctx, pkt);
    // mux.unlock();
    //释放引用
    av_packet_free(&pkt);

    return ret != 0 ? false : true;
}

AVFrame *Decoder::getDecodedFrame()
{
    if (!codec_ctx)
    {
        mux.unlock();
        return NULL;
    }
    AVFrame *frame = av_frame_alloc();
    int ret = avcodec_receive_frame(codec_ctx, frame);
    if (ret != 0)
    {
        av_frame_free(&frame);
        return NULL;
    }
    return frame;
}
